package com.cy.mall.comm.utils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.servlet.http.HttpServletRequest;

import org.springframework.util.Base64Utils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import com.cy.mall.comm.constant.Constants;
import com.cy.mall.model.enums.Sex;
import com.cy.mall.model.enums.SmsType;

import lombok.extern.slf4j.Slf4j;

/**
 * 工具类
 *
 * @author: tanyilin
 * @create: 2018年10月26日 下午2:49:43
 */
@Slf4j
public class CommonUtils {

	public static void main(String[] arg) {
		String str = "2018-09-09 15:22:17";
		System.out.println(str.substring(8, 10));
		System.out.println(md5("6tj4u".concat(dateFormat3(new Date()))));
		System.out.println(System.currentTimeMillis());
		System.out.println(UUID.randomUUID().toString());
		System.out.println(SHA256Utils.getSha256Str("fjChnlCode=xxx&productType=xxx&mobileNo=xx"));
	}
	
	/**
	 * 2003的Excel
	 * 
	 * @param filePath
	 * @return
	 */
    public static boolean isExcel2003(String filePath) {
        return filePath.matches("^.+\\.(?i)(xls)$");
    }

    /**
     * 2007的Excel
     * 
     * @param filePath
     * @return
     */
    public static boolean isExcel2007(String filePath) {
        return filePath.matches("^.+\\.(?i)(xlsx)$");
    }

    /**
     * 时间戳 ---》 日期时间格式
     * @param timeStamp
     * @return java.util.Date
     */
    public static Date timeStamp2Date(Long timeStamp) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(timeStamp);
        String dateStr = sdf.format(date);
        return parseDate(dateStr);
    }

	/**
     * 时间格式化：日期 --> 字符串 : yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return
     */
    public static String dateFormat(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat(Constants.yyyy_MM_dd_HH_mm_ss);
        return sdf.format(date);
    }

    /**
     * 时间格式化：日期 --> 字符串 : yyyy年MM月dd日 HH:mm
     *
     * @param date
     * @return
     */
	public static String dateFormat2(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
        return sdf.format(date);
	}
    
	/**
	 * 时间格式化：日期 --> 字符串 : yyyyMMdd
	 * 
	 * @param date
	 * @return
	 */
	public static String dateFormat3(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        return sdf.format(date);
	}

    public static String dateFormat4(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月");
        return sdf.format(date);
    }
	
    /**
     * 字符串转时间：字符串 --> 日期
     *
     * @param str
     * @return
     */
    public static Date parseDate(String str) {
        SimpleDateFormat sdf = new SimpleDateFormat(Constants.yyyy_MM_dd_HH_mm_ss);
        Date date = null;
        try {
            date = sdf.parse(str);
        } catch (ParseException e) {
            log.error("parseDate error:", e);
        }
        return date;
    }

    /**
     * 字符串转时间：字符串 --> 日期 19950818 --> 1995-08-18
     * @param str
     * @return java.util.Date
     */
    public static Date parseDate2(String str) {
        if(CommonUtils.isEmpty(str)) {
            return null;
        }
        if(str.length() != 8) {
            return null;
        }
        String dateStr = str.substring(0, 4).concat("-").concat(str.substring(4, 6)).concat("-").concat(str.substring(6));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException e) {
            log.error("parseDate2 error:", e);
        }
        return date;
    }

    /**
     * 计算日期 X （小时、日、月）之后/之前
     * 
     * @param date 日期
     * @param amount 数量
     * @param unit 单位
     * @return
     */
    public static Date addTime(Date date, int amount, int unit) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(unit, amount);
        return calendar.getTime();
    }
    
    /**
     * 计算时间相差天数，date2 - date1
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int diffDays(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return 0;
        }
        int days = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
        return days;
    }
    
    /**
     * 得到某一天的开始时间
     *
     * @param date
     * @return
     */
    public static Date getDayStartTime(Date date) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }
    
    /**
     * 得到某一天的结束时间
     *
     * @param date
     * @return
     */
    public static Date getDayEndTime(Date date) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }
    
    /**
     * 得到某个日期当月的第一天
     *
     * @param date
     * @return
     */
    public static Date getMonthStartTime(Date date) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        return getMonthStartTime(calendar);
    }
    
    /**
     * 得到某个日期当月的第一天
     *
     * @param calendar
     * @return
     */
    public static Date getMonthStartTime(Calendar calendar) {
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }
    
    /**
     * 得到某个日期当月的最后一天
     *
     * @param date
     * @return
     */
    public static Date getMonthEndTime(Date date) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        return getMonthEndTime(calendar);
    }
    
    /**
     * 得到某个日期当月的最后一天
     *
     * @param calendar
     * @return
     */
    public static Date getMonthEndTime(Calendar calendar) {
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }
    
    /**
     * 得到某个日期的周一
     * 
     * @param date
     * @return
     */
    public static Date getThisWeekMonday(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		// 获得当前日期是一个星期的第几天
		int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
		if (1 == dayWeek) {
			cal.add(Calendar.DAY_OF_MONTH, -1);
		}
		// 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		// 获得当前日期是一个星期的第几天
		int day = cal.get(Calendar.DAY_OF_WEEK);
		// 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
		cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
		return cal.getTime();
	}
    
    /**
     * 获取季节
     *
     * @param month
     * @return
     */
    public static Integer getQuarter(int month) {
        if (month >= 1 && month <= 3) {
            return 1;
        } else if (month >= 4 && month <= 6) {
            return 2;
        } else if (month >= 7 && month <= 9) {
            return 3;
        } else if (month >= 10 && month <= 12) {
            return 4;
        }
        return null;
    }
    
    /**
     * 得到某个日期当季的最后一天
     *
     * @param time
     * @return
     */
    public static Date getQuarterEndTime(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        int month = calendar.get(Calendar.MONTH) + 1;
        int quarter = getQuarter(month);
        switch (quarter) {
            case 1:
                month = 3;
                break;

            case 2:
                month = 6;
                break;

            case 3:
                month = 9;
                break;

            case 4:
                month = 12;
                break;

            default:
                break;
        }
        calendar.set(Calendar.MONTH, month - 1);
        return getMonthEndTime(calendar);
    }
    
    /**
     * 得到某个日期当季的第一天
     *
     * @param time
     * @return
     */
    public static Date getQuarterStartTime(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        int month = calendar.get(Calendar.MONTH) + 1;
        int quarter = getQuarter(month);
        switch (quarter) {
            case 1:
                month = 1;
                break;

            case 2:
                month = 4;
                break;

            case 3:
                month = 7;
                break;

            case 4:
                month = 10;
                break;

            default:
                break;
        }
        calendar.set(Calendar.MONTH, month - 1);
        return getMonthStartTime(calendar);
    }
    
    /**
     * 获取某个日期的月份
     *
     * @param time
     * @return
     */
    public static Integer getMonth(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        int month = calendar.get(Calendar.MONTH) + 1;
        return month;
    }
    
    /**
     * 获取某个日期的年份
     *
     * @param time
     * @return
     */
    public static Integer getYear(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        int year = calendar.get(Calendar.YEAR);
        return year;
    }
    
    /**
     * 判断是否微信客户端请求
     *
     * @param request
     * @return
     */
    public static boolean isWechatClient(HttpServletRequest request) {
        String userAgent = request.getHeader("user-agent");
        if (StringUtils.isEmpty(userAgent)) {
            return false;
        }
        return userAgent.toLowerCase().indexOf("micromessenger") > 0;

    }
    
    /**
     * 获取请求IP
     *
     * @param request
     * @return
     */
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
    
    /**
     * 对字符串进行 32位 md5 加密
     *
     * @param value
     * @return
     */
    public static String md5(String value) {
        //对字符串进行 32位 md5 加密
        return DigestUtils.md5DigestAsHex(value.getBytes());
    }
    
    /**
     * 密码 进行  base64 加盐加密
     *
     * @param value
     * @return
     */
    public static String md5Passwod(String value) {
        String salt = Constants.SLAT;
        value = Base64Utils.encodeToString(value.concat(salt).getBytes());
        value = md5(value.concat(salt));
        return value;
    }
    
    /**
     * 生成 X 位随机数
     *
     * @param length
     * @return
     */
    public static String randomNumber(int length) {
        Random random = new Random();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < length; i++) {
            stringBuilder.append(random.nextInt(10));
        }
        return stringBuilder.toString();
    }
    
    /**
     * 带百分号的乘法
     *
     * @param a
     * @param b
     * @return
     */
    public static BigDecimal multiplyWithPercent(BigDecimal a, BigDecimal b) {
        return multiplyWithPercent(a, b, 2);
    }
    
    /**
     * 带百分号的乘法
     *
     * @param a
     * @param b
     * @param scale
     * @return
     */
    public static BigDecimal multiplyWithPercent(BigDecimal a, BigDecimal b, int scale) {
        return a.multiply(b).divide(new BigDecimal("100"), scale, BigDecimal.ROUND_HALF_UP);
    }
    
    /**
     * 判断List是否为空
     * 
     * @param list
     * @return
     */
    public static boolean isEmpty(List<?> list) {
    	return (list == null || list.isEmpty());
    }
    
    /**
     * 判断一个对象是否为空
     * 
     * @param object
     * @return
     */
    public static boolean isEmpty(Object object) {
    	return (object == null || "".equals(object));
    }
    
    /**
     * 生成当前时间加上4位随机数的字符串，形式："yyyyMMddHHmmssSSS" + "xxxx"
     * 
     * @return
     */
    public static String getCurrentTimeAndRandomNumber() {
    	SimpleDateFormat sdf = new SimpleDateFormat(Constants.yyyyMMddHHmmssSSS);
    	return sdf.format(new Date()).concat(randomNumber(4));
    }

    /**
     * 判断性别 0-女，1-男
     * @param sexText
     * @return int
     */
    public static int getSexByText(String sexText) {
        if(StringUtils.isEmpty(sexText)) {
            return -1;
        }
        if("男".equals(sexText)) {
            return 1;
        }
        if("女".equals(sexText)) {
            return 0;
        }
        return -1;
    }

    /**
     * 通过身份证号码判断性别
     *
     * @param idNo
     * @return
     */
    public static Sex getSexByIdNo(String idNo) {
        if (StringUtils.isEmpty(idNo)) {
            return Sex.UNKNOW;
        }
        int length = idNo.length();
        if (length == 15) {
            // 15位身份证号码
            String usex = idNo.substring(14, 15);
            if (Integer.parseInt(usex) % 2 == 0) {
                // 女
                return Sex.FEMALE;
            } else {
                // 男
                return Sex.MALE;
            }
        } else if (length == 18) {
            // 18位身份证号码
            String usex = idNo.substring(16).substring(0, 1);
            if (Integer.parseInt(usex) % 2 == 0) {
                // 女
                return Sex.FEMALE;
            } else {
                // 男
                return Sex.MALE;
            }
        } else {
            return Sex.UNKNOW;
        }
    }
    
    /**
     * 通过身份证号码得到年龄
     * 
     * @param idNo
     * @return
     */
    public static int getAgeByIdNo(String idNo) {
    	if (StringUtils.isEmpty(idNo)) {
            return 0;
        }
    	int length = idNo.length();
    	int age = 0;
    	int year = Calendar.getInstance().get(Calendar.YEAR);
    	if(length == 15) {
    		age = year - Integer.parseInt("19" + idNo.substring(6, 8));
    	}else if(length == 18) {
    		age = year - Integer.parseInt(idNo.substring(6, 10));
    	}
    	
    	return age;
    }
    
    /**
     * 姓名脱敏
     * 
     * @param str
     * @return
     */
    public static String nameFormat(String str) {
    	if(StringUtils.isEmpty(str)) {
    		return str;
    	}
        String lastStr = str.substring(str.length() - 1);
        if (str.length() < 3) {
            return "*".concat(lastStr);
        }
        String beforeStr = str.substring(0, 1);
        return beforeStr.concat("*").concat(lastStr);
    }

    /**
     * 手机号码 脱敏 138 **** 0001
     * @param mobile
     * @return java.lang.String
     */
    public static String mobileFormat(String mobile) {
        if(StringUtils.isEmpty(mobile) || mobile.length() != 11 ) {
            return mobile;
        }

        String beforeStr = mobile.substring(0, 3);
        String lastStr = mobile.substring(mobile.length() - 4);
        return beforeStr.concat(" **** ").concat(lastStr);

    }

    /**
     * 银行卡号 脱敏 ： **** 1234
     * @param bankCardAccount
     * @return java.lang.String
     */
    public static String bankCardAccountFormat(String bankCardAccount) {

        if(StringUtils.isEmpty(bankCardAccount) || bankCardAccount.length() < 4) {
            return bankCardAccount;
        }

        String lastStr = bankCardAccount.substring(bankCardAccount.length() - 4);

        return "**** ".concat(lastStr);
    }

    /**
     * 银行卡号 脱敏 ： **** **** **** 1234
     * @param bankCardAccount
     * @return java.lang.String
     */
    public static String bankCardAccountFormat2(String bankCardAccount) {

        if(StringUtils.isEmpty(bankCardAccount) || bankCardAccount.length() < 4) {
            return bankCardAccount;
        }

        String lastStr = bankCardAccount.substring(bankCardAccount.length() - 4);

        return "**** **** **** ".concat(lastStr);
    }

    /**
     * 根据'逾期日期'计算动态'逾期天数' = 系统当前时间 - 逾期日期
     * 
     * @param overdueDate
     * @return
     */
    public static int getOverdueDays(Date overdueDate) {
    	if(isEmpty(overdueDate)) {
    		return -1;
    	}
    	//系统当前时间 - 逾期日期 + 1
    	return diffDays(overdueDate, new Date());
    }
    
    /**
     * 短信验证码key
     *
     * @param mobile
     * @param smsType
     * @return
     */
    public static String smsCodeKey(String mobile, SmsType smsType) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(Constants.SMS_CODE);
        stringBuilder.append(mobile);
        stringBuilder.append("-");
        stringBuilder.append(smsType.name());
        return stringBuilder.toString();
    }
    
    /**
     * 生成随机数
     *
     * @param scale
     * @return
     */
    public static String randomCode(int scale) {
        StringBuilder stringBuilder = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < scale; i++) {
            stringBuilder.append(random.nextInt(10));
        }
        return stringBuilder.toString();
    }

    /**
     * java Bean 转 map，使用 LinkedHashMap 保证输出顺序按照添加顺序一致
     * @param beanObj
     * @return java.util.LinkedHashMap<K,V>
     */
    public static <K, V> LinkedHashMap<K, V> bean2Map(Object beanObj) throws Exception {
        if(beanObj == null){
            return null;
        }
        LinkedHashMap<K, V> map = new LinkedHashMap<>();

        //获取所有的属性
        Field[] declaredFields = beanObj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            //打破封装，设置可访问
            field.setAccessible(true);
            map.put((K)field.getName(), (V)field.get(beanObj));
        }
        return map;
    }

    /**
     * java Bean 转 map, key 全为大写字母，使用 LinkedHashMap 保证输出顺序按照添加顺序一致
     * @param beanObj
     * @return java.util.LinkedHashMap<K,V>
     */
    public static <K, V> LinkedHashMap<K, V> bean2MapUpperKey(Object beanObj) throws Exception {
        if(beanObj == null){
            return null;
        }
        LinkedHashMap<K, V> map = new LinkedHashMap<>();

        //获取所有的属性
        Field[] declaredFields = beanObj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            //打破封装，设置可访问
            field.setAccessible(true);
            map.put((K)field.getName().toUpperCase(), (V)new BigDecimal(field.get(beanObj).toString()).multiply(new BigDecimal(10000)).setScale(2).toString());
        }
        return map;
    }

    /**
     * 拼接 参数 字符串，形如：param1=xx&param2=xxx
     * @param params
     * @return java.lang.String
     */
    public static String getParamStr(Map<String, Object> params) {
        StringBuffer sb = new StringBuffer();
        for (String k : params.keySet()) {
            sb.append(k).append("=").append(params.get(k).toString()).append("&");
        }
        return sb.toString().substring(0, sb.length() - 1);
    }

    /**
     * 检查 Object 里面是否有属性字段为空
     * @param beanObj
     * @return boolean
     */
    public static boolean objectFieldsIsEmpty(Object beanObj) {
        if(beanObj == null){
            return true;
        }
        boolean fieldsIsEmpty = false;
        //获取所有的属性
        Field[] declaredFields = beanObj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            //打破封装，设置可访问
            field.setAccessible(true);
            try {
                if(isEmpty(field.get(beanObj))) {
                    fieldsIsEmpty = true;
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return fieldsIsEmpty;
    }

    /**
     * 最近三年
     * @param
     * @return java.util.List<java.lang.Integer>
     */
    public static List<Integer> getRecent3Year() {
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
        int thisYear = Integer.parseInt(sdf.format(now));

        List<Integer> list = new ArrayList<>();
        list.add(thisYear);
        list.add(thisYear - 1);
        list.add(thisYear - 2);

        return list;
    }

}
